#include "main.h"
#include "string.h"
#include "spi.h"
#include "lcd.h"
#include "spi.h"
#include "stdlib.h"

void delay_us(unsigned int _us_time)
{
  volatile unsigned int i;
  for (i = 0; i < (_us_time * (SystemCoreClock / 1000000 / 5)); i++)
  {
    __NOP();
  }
}

void Delay_ms(unsigned int _ms_time)
{
  HAL_Delay(_ms_time);
}

void SPI_SendByte(unsigned char byte)
{
  HAL_SPI_Transmit(&hspi1, &byte, 1, 1000);
}

void TFT_SEND_CMD(unsigned char o_command)
{
  TFT_DC_0;

  SPI_SendByte(o_command);
}

void TFT_SEND_DATA(unsigned char o_data)
{
  TFT_DC_1;

  SPI_SendByte(o_data);
}

void TFT_SET_ADD(unsigned short int X, unsigned short int Y, unsigned short int X_END, unsigned short int Y_END)
{

  if ((X_END > (TFT_COLUMN_NUMBER - 1)) || (X > (TFT_COLUMN_NUMBER - 1)))
  {
    X_END = (TFT_COLUMN_NUMBER - 1);
    // X = 0;
  }
  if ((Y_END > (TFT_LINE_NUMBER - 1)) || (Y > (TFT_LINE_NUMBER - 1)))
  {
    // Y = 0;
    Y_END = (TFT_LINE_NUMBER - 1);
  }
  TFT_SEND_CMD(0x2A);
  TFT_SEND_DATA(X >> 8);
  TFT_SEND_DATA(X); // start column
  TFT_SEND_DATA(X_END >> 8);
  TFT_SEND_DATA(X_END); // start column
  TFT_SEND_CMD(0x2B);
  TFT_SEND_DATA(Y >> 8);
  TFT_SEND_DATA(Y); // start row
  TFT_SEND_DATA(Y_END >> 8);
  TFT_SEND_DATA(Y_END); // start row
  TFT_SEND_CMD(0x2C);
}

void TFT_Clear(unsigned short int back_c)
{
  unsigned int ROW = 0, column = 0;
  TFT_SET_ADD(0x0000, 0x0000, TFT_COLUMN_NUMBER - 1, TFT_LINE_NUMBER - 1);
  for (ROW = 0; ROW < TFT_LINE_NUMBER; ROW++) // ROW loop
  {
    for (column = 0; column < TFT_COLUMN_NUMBER; column++) // column loop
    {
      TFT_SEND_DATA(back_c >> 8);
      TFT_SEND_DATA(back_c);
    }
  }
}

void TFT_DrawBuf(unsigned char *buf, unsigned short x, unsigned short y, unsigned short w, unsigned short h)
{
  uint32_t len;
  TFT_SET_ADD(x, y, x + w - 1, y + h - 1);
  TFT_DC_1;
  len = w * h * 2;
  while (len > 65535)
  {
    HAL_SPI_Transmit(&hspi1, buf, 65535, 1000);
    buf += 65535;
    len -= 65535;
  }
  HAL_SPI_Transmit(&hspi1, buf, len, 1000);

  // TFT_CS_1;
}

void TFT_Init(void)
{
  TFT_BL_1;
  TFT_RST_0;
  Delay_ms(100);
  TFT_RST_1;
  Delay_ms(1000);
  //-----------------------ST7789V Frame rate setting-----------------//
  //************************************************
  TFT_SEND_CMD(0x3A); // 65k mode
  TFT_SEND_DATA(0x05);
  TFT_SEND_CMD(0xC5); // VCOM
  TFT_SEND_DATA(0x1A);
  TFT_SEND_CMD(0x36);

#if (DIS_DIR == 0)
  TFT_SEND_DATA(0x00);
#elif (DIS_DIR == 1)
  TFT_SEND_DATA(0xA0);
#elif (DIS_DIR == 2)
  TFT_SEND_DATA(0xC0);
#elif (DIS_DIR == 3)
  TFT_SEND_DATA(0x60);
#endif
  //-------------ST7789V Frame rate setting-----------//
  TFT_SEND_CMD(0xb2); // Porch Setting
  TFT_SEND_DATA(0x05);
  TFT_SEND_DATA(0x05);
  TFT_SEND_DATA(0x00);
  TFT_SEND_DATA(0x33);
  TFT_SEND_DATA(0x33);

  TFT_SEND_CMD(0xb7);  // Gate Control
  TFT_SEND_DATA(0x05); // 12.2v   -10.43v
  //--------------ST7789V Power setting---------------//
  TFT_SEND_CMD(0xBB); // VCOM
  TFT_SEND_DATA(0x2F);

  TFT_SEND_CMD(0xC0); // Power control
  TFT_SEND_DATA(0x2c);

  TFT_SEND_CMD(0xC2); // VDV and VRH Command Enable
  TFT_SEND_DATA(0x01);

  TFT_SEND_CMD(0xC3);  // VRH Set
  TFT_SEND_DATA(0x0F); // 4.3+( vcom+vcom offset+vdv)

  TFT_SEND_CMD(0xC4);  // VDV Set
  TFT_SEND_DATA(0x20); // 0v

  TFT_SEND_CMD(0xC6);  // Frame Rate Control in Normal Mode
  TFT_SEND_DATA(0X01); // 111Hz

  TFT_SEND_CMD(0xd0); // Power Control 1
  TFT_SEND_DATA(0xa4);
  TFT_SEND_DATA(0xa1);

  TFT_SEND_CMD(0xE8); // Power Control 1
  TFT_SEND_DATA(0x03);

  TFT_SEND_CMD(0xE9); // Equalize time control
  TFT_SEND_DATA(0x09);
  TFT_SEND_DATA(0x09);
  TFT_SEND_DATA(0x08);
  //---------------ST7789V gamma setting-------------//
  TFT_SEND_CMD(0xE0); // Set Gamma
  TFT_SEND_DATA(0xD0);
  TFT_SEND_DATA(0x05);
  TFT_SEND_DATA(0x09);
  TFT_SEND_DATA(0x09);
  TFT_SEND_DATA(0x08);
  TFT_SEND_DATA(0x14);
  TFT_SEND_DATA(0x28);
  TFT_SEND_DATA(0x33);
  TFT_SEND_DATA(0x3F);
  TFT_SEND_DATA(0x07);
  TFT_SEND_DATA(0x13);
  TFT_SEND_DATA(0x14);
  TFT_SEND_DATA(0x28);
  TFT_SEND_DATA(0x30);

  TFT_SEND_CMD(0XE1); // Set Gamma
  TFT_SEND_DATA(0xD0);
  TFT_SEND_DATA(0x05);
  TFT_SEND_DATA(0x09);
  TFT_SEND_DATA(0x09);
  TFT_SEND_DATA(0x08);
  TFT_SEND_DATA(0x03);
  TFT_SEND_DATA(0x24);
  TFT_SEND_DATA(0x32);
  TFT_SEND_DATA(0x32);
  TFT_SEND_DATA(0x3B);
  TFT_SEND_DATA(0x14);
  TFT_SEND_DATA(0x13);
  TFT_SEND_DATA(0x28);
  TFT_SEND_DATA(0x2F);

  TFT_SEND_CMD(0x20);
  TFT_SEND_CMD(0x11); // Exit Sleep
  Delay_ms(120);
  TFT_SEND_CMD(0x29); // Display on
  TFT_BL_1;
}

// 类C++ 写法
static void _setTextColor(uint16_t color)
{
  tft.fontcolor = color;
}

static void _setFreeFont(void)
{
}

static void _flash(void)
{
  for (uint8_t i = 0; i < 240; i++)
  {
    TFT_SET_ADD(0, i, 319, i);
    TFT_DC_1;
    // HAL_SPI_Transmit(&hspi1, (uint8_t *)tft.buf[i], 320 * 2, 1000);
  }
}
#define swap_coord(a, b) \
  do                     \
  {                      \
    int16_t t = a;       \
    a = b;               \
    b = t;               \
  } while (0)
static void _drawPixel(uint16_t x, uint16_t y, uint16_t color)
{
  if ((x >= 320) || (y >= 280))
    return;
  uint8_t d[2] = {color >> 8, color};
  TFT_SET_ADD(x, y, x, y);
  TFT_DC_1;
  HAL_SPI_Transmit(&hspi1, d, 2, 1000);
  // tft.buf[y][x] = (color >> 8) | (color << 8);
}

static void _drawFastVLine(uint16_t x, uint16_t y, int h, uint16_t color)
{
  uint8_t buf[240 * 2];
  if (h >= 0)
  {
    if (y + h >= 240)
    {
      h = 240 - y;
    }
    TFT_SET_ADD(x, y, x, y + h - 1);
    TFT_DC_1;
    for (int i = 0; i < h; i++)
    {
      buf[i * 2] = color >> 8;
      buf[i * 2 + 1] = color;
    }
    HAL_SPI_Transmit(&hspi1, buf, h * 2, 1000);
  }
  else
  {
    h = -h;
    if (y - h + 1 < 0)
    {
      h = y + 1;
    }
    TFT_SET_ADD(x, y - h + 1, x, y);
    TFT_DC_1;
    for (int i = 0; i < h; i++)
    {
      buf[i * 2] = color >> 8;
      buf[i * 2 + 1] = color;
    }
    HAL_SPI_Transmit(&hspi1, buf, h * 2, 1000);
  }
}

static void _drawFastHLine(uint16_t x, uint16_t y, int w, uint16_t color)
{
  uint8_t buf[320 * 2];
  if (w >= 0)
  {
    if (w + x > 320)
    {
      w = 320 - x;
    }
    for (int i = 0; i < w; i++)
    {
      buf[i * 2] = color >> 8;
      buf[i * 2 + 1] = color;
    }
    TFT_SET_ADD(x, y, x + w - 1, y);
    TFT_DC_1;
    HAL_SPI_Transmit(&hspi1, buf, w * 2, 1000);
  }
  else
  {
    w = -w;
    if (x - w + 1 < 0)
    {
      w = x + 1;
    }
    for (int i = 0; i < w; i++)
    {
      buf[i * 2] = color >> 8;
      buf[i * 2 + 1] = color;
    }
    TFT_SET_ADD(x - w + 1, y, x, y);
    TFT_DC_1;
    HAL_SPI_Transmit(&hspi1, buf, w * 2, 1000);
  }
}

static void _drawBitmap(uint16_t x, uint16_t y, const uint8_t *bitmap, uint16_t w, uint16_t h, uint16_t color)
{

  for (uint16_t j = 0; j < h; j++)
  {
    for (uint16_t i = 0; i < w; i++)
    {
      if (bitmap[j * (w / 8 + 1) + i / 8] & (0x80 >> ((i) % 8)))
      {
        _drawPixel(x + i, y + j, color);
      }
    }
  }
}

static void _drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color)
{
  int steep = abs(y1 - y0) > abs(x1 - x0);
  if (steep)
  {
    swap_coord(x0, y0);
    swap_coord(x1, y1);
  }

  if (x0 > x1)
  {
    swap_coord(x0, x1);
    swap_coord(y0, y1);
  }

  int dx = x1 - x0, dy = abs(y1 - y0);
  int err = dx >> 1, ystep = -1, xs = x0, dlen = 0;
  if (y0 < y1)
    ystep = 1;

  if (steep)
  {
    for (; x0 <= x1; x0++)
    {
      dlen++;
      err -= dy;
      if (err < 0)
      {
        if (dlen == 1)
          _drawPixel(y0, xs, color);
        else
          _drawFastVLine(y0, xs, dlen, color);
        dlen = 0;
        y0 += ystep;
        xs = x0 + 1;
        err += dx;
      }
    }
    if (dlen)
      _drawFastVLine(y0, xs, dlen, color);
  }
  else
  {
    for (; x0 <= x1; x0++)
    {
      dlen++;
      err -= dy;
      if (err < 0)
      {
        if (dlen == 1)
          _drawPixel(xs, y0, color);
        else
          _drawFastHLine(xs, y0, dlen, color);
        dlen = 0;
        y0 += ystep;
        xs = x0 + 1;
        err += dx;
      }
    }
    if (dlen)
      _drawFastHLine(xs, y0, dlen, color);
  }
}

static void _drawRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color)
{
  _drawFastHLine(x, y, w, color);
  _drawFastHLine(x, y + h - 1, w, color);
  _drawFastVLine(x, y + 1, h - 2, color);
  _drawFastVLine(x + w - 1, y + 1, h - 2, color);
}

static void _drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, uint16_t color)
{
  if (rx < 2)
    return;
  if (ry < 2)
    return;
  int32_t x, y;
  int32_t rx2 = rx * rx;
  int32_t ry2 = ry * ry;
  int32_t fx2 = 4 * rx2;
  int32_t fy2 = 4 * ry2;
  int32_t s;

  for (x = 0, y = ry, s = 2 * ry2 + rx2 * (1 - 2 * ry); ry2 * x <= rx2 * y; x++)
  {
    _drawPixel(x0 + x, y0 + y, color);
    _drawPixel(x0 - x, y0 + y, color);
    _drawPixel(x0 - x, y0 - y, color);
    _drawPixel(x0 + x, y0 - y, color);
    if (s >= 0)
    {
      s += fx2 * (1 - y);
      y--;
    }
    s += ry2 * ((4 * x) + 6);
  }
  for (x = rx, y = 0, s = 2 * rx2 + ry2 * (1 - 2 * rx); rx2 * y <= ry2 * x; y++)
  {
    _drawPixel(x0 + x, y0 + y, color);
    _drawPixel(x0 - x, y0 + y, color);
    _drawPixel(x0 - x, y0 - y, color);
    _drawPixel(x0 + x, y0 - y, color);
    if (s >= 0)
    {
      s += fy2 * (1 - x);
      x--;
    }
    s += rx2 * ((4 * y) + 6);
  }
}

static void _fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color)
{
  if (w == 0 || h == 0)
  {
    return;
  }
  if (w > h)
  {
    for (int32_t i = 0; i < h; i++)
    {
      _drawFastHLine(x, y + i, w, color);
    }
  }
  else
  {
    for (int32_t i = 0; i < w; i++)
    {
      _drawFastVLine(x + i, y, h, color);
    }
  }
  // for (int32_t i = x; i < x + w; i++)
  // {
  //   for (int32_t j = y; j < y + h; j++)
  //   {
  //     _drawPixel(i, j, color);
  //   }
  // }
}

extern const unsigned char font[];
static void _drawChar(char c, int32_t x, int32_t y, uint16_t color)
{
  for (int8_t i = 0; i < 5; i++)
  {
    for (int8_t j = 1; j < 8; j++)
    {
      if (font[c * 5 + i] & (0x80 >> j))
      {
        _fillRect(x + i * tft.textsize, y - (j - 7) * tft.textsize, tft.textsize, tft.textsize, color);
      }
    }
  }
}

static void _drawString(const char *string, int32_t poX, int32_t poY)
{
  int len = strlen(string);
  for (int i = 0; i < len; i++)
  {
    _drawChar(string[i], poX, poY, tft.fontcolor);
    poX += tft.textsize * 6;
  }
}

static void _setTextSize(uint8_t size)
{
  tft.textsize = size;
}

static void drawParaV(int x, int y, int w, int color)
{
  for (int i = 0; i < w; i++)
  {
    tft.drawLine(x - i, y + i, x + i, y + i, color);
  }
  for (int i = 0; i < 4 * w; i++)
  {
    tft.drawLine(x - w, y + w + i, x + w, y + w + i, color);
  }
  for (int i = 0; i < w; i++)
  {
    tft.drawLine(x + i - w + 1, y + i + 5 * w, x + w - i - 1, y + i + 5 * w, color);
  }
}

static void drawParaH(int x, int y, int w, int color)
{
  for (int i = 0; i < w; i++)
  {
    tft.drawLine(x + i, y - i, x + i, y + i, color);
  }
  for (int i = 0; i < 4 * w; i++)
  {
    tft.drawLine(x + w + i, y - w, x + w + i, y + w, color);
  }
  for (int i = 0; i < w; i++)
  {
    tft.drawLine(x + i + 5 * w, y - w + i + 1, x + i + 5 * w, y + w - i - 1, color);
  }
}

static void _drawPara(int x, int y, int w, int pix, uint16_t color, int num, int last_num)
{
  if (num < 0 || num > 11)
  {
    return;
  }
  const char image[12] = {
      0x3F, // 0: 0011 1111
      0x06, // 1: 0000 0110
      0x5B, // 2: 0101 1011
      0x4F, // 3: 0100 1111
      0x66, // 4: 0110 0110
      0x6D, // 5: 0110 1101
      0x7D, // 6: 0111 1101
      0x07, // 7: 0000 0111
      0x7F, // 8: 0111 1111
      0x6F, // 9: 0110 1111
      0x40, // 10: 0100 0000
      0x00, // 11: 0000 0000
  };
  // 段0 (已处理)
  if (image[num] & (1 << 0))
  {
    if (!(image[last_num] & (1 << 0)))
    {
      drawParaH(x, y, w, color);
    }
  }
  else
  {
    if ((image[last_num] & (1 << 0)))
    {
      drawParaH(x, y, w, BLACK);
    }
  }

  // 段1
  if (image[num] & (1 << 1))
  {
    if (!(image[last_num] & (1 << 1)))
    {
      drawParaV(x + 6 * w - 1 + pix, y + pix, w, color);
    }
  }
  else
  {
    if ((image[last_num] & (1 << 1)))
    {
      drawParaV(x + 6 * w - 1 + pix, y + pix, w, BLACK);
    }
  }

  // 段2
  if (image[num] & (1 << 2))
  {
    if (!(image[last_num] & (1 << 2)))
    {
      drawParaV(x + 6 * w - 1 + pix, y + 3 * pix + 6 * w - 1, w, color);
    }
  }
  else
  {
    if ((image[last_num] & (1 << 2)))
    {
      drawParaV(x + 6 * w - 1 + pix, y + 3 * pix + 6 * w - 1, w, BLACK);
    }
  }

  // 段3
  if (image[num] & (1 << 3))
  {
    if (!(image[last_num] & (1 << 3)))
    {
      drawParaH(x, y + 12 * w - 2 + 4 * pix, w, color);
    }
  }
  else
  {
    if ((image[last_num] & (1 << 3)))
    {
      drawParaH(x, y + 12 * w - 2 + 4 * pix, w, BLACK);
    }
  }

  // 段4
  if (image[num] & (1 << 4))
  {
    if (!(image[last_num] & (1 << 4)))
    {
      drawParaV(x - pix, y + 3 * pix + 6 * w - 1, w, color);
    }
  }
  else
  {
    if ((image[last_num] & (1 << 4)))
    {
      drawParaV(x - pix, y + 3 * pix + 6 * w - 1, w, BLACK);
    }
  }

  // 段5
  if (image[num] & (1 << 5))
  {
    if (!(image[last_num] & (1 << 5)))
    {
      drawParaV(x - pix, y + pix, w, color);
    }
  }
  else
  {
    if ((image[last_num] & (1 << 5)))
    {
      drawParaV(x - pix, y + pix, w, BLACK);
    }
  }

  // 段6
  if (image[num] & (1 << 6))
  {
    if (!(image[last_num] & (1 << 6)))
    {
      drawParaH(x, y + 6 * w - 1 + 2 * pix, w, color);
    }
  }
  else
  {
    if ((image[last_num] & (1 << 6)))
    {
      drawParaH(x, y + 6 * w - 1 + 2 * pix, w, BLACK);
    }
  }
}

struct tft_dev tft = {
    .buf = {0},
    .drawBitmap = _drawBitmap,
    .drawChar = _drawChar,
    .drawEllipse = _drawEllipse,
    .drawFastHLine = _drawFastHLine,
    .drawFastVLine = _drawFastVLine,
    .drawLine = _drawLine,
    .drawPixel = _drawPixel,
    .drawRect = _drawRect,
    .drawString = _drawString,
    .drawNixie = _drawPara,
    .fillRect = _fillRect,
    .flash = _flash,
    .init = TFT_Init,
    .setFreeFont = _setFreeFont,
    .setTextColor = _setTextColor,
    .setTextSize = _setTextSize,
    .textfont = 1,
    .textsize = 1,
    .fontcolor = 0xFFFF,
};

// void TFT()
// {
//   memset(tft.buf, 0, sizeof(tft.buf));
//   tft.fontcolor = 0xFFFF;
//   tft.textfont = 1;
//   tft.textsize = 2;
//   tft.init = TFT_Init;
//   tft.setTextSize = _setTextSize;
//   tft.flash = _flash;
//   tft.setFreeFont = _setFreeFont;
//   tft.setTextColor = _setTextColor;
//   tft.drawPixel = _drawPixel;
//   tft.drawFastVLine = _drawFastVLine;
//   tft.drawFastHLine = _drawFastHLine;
//   tft.drawBitmap = _drawBitmap;
//   tft.drawLine = _drawLine;
//   tft.drawRect = _drawRect;
//   tft.drawEllipse = _drawEllipse;
//   tft.fillRect = _fillRect;
//   tft.drawChar = _drawChar;
//   tft.drawString = _drawString;
// }
